﻿using ServiceStack.Text;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StackExchange.Redis
{
    public static class TypedHashExtensionMethods
    {
        public static TItem[] HashGet<TItem>(this IDatabase database, RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None)
        {
            var values = database.HashGet(key, hashFields, flags);
            if (values == null) return null;
            if (values.Length == 0) return new TItem[0];
            var items = new TItem[values.Length];
            for (int i = 0; i < values.Length; i++)
            {
                items[i] = JsonSerializer.DeserializeFromString<TItem>(values[i]);
            }

            return items;
        }

        public static Task<TItem[]> HashGetAsync<TItem>(this IDatabase database, RedisKey key, RedisValue[] hashFields, CommandFlags flags = CommandFlags.None)
        {
            return database.HashGetAsync(key, hashFields, flags).ContinueWith(task =>
            {
                var values = task.Result;
                if (values == null) return null;
                if (values.Length == 0) return new TItem[0];
                var items = new TItem[values.Length];
                for (int i = 0; i < values.Length; i++)
                {
                    items[i] = JsonSerializer.DeserializeFromString<TItem>(values[i]);
                }
                return items;
            });
        }

        public static TItem HashGet<TItem>(this IDatabase database, RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None)
        {
            var value = database.HashGet(key, hashField, flags);
            if (value.HasValue)
            {
                var item = JsonSerializer.DeserializeFromString<TItem>(value);
                return item;
            }
            else
            {
                return default(TItem);
            }
        }
        public static Task<TItem> HashGetAsync<TItem>(this IDatabase database, RedisKey key, RedisValue hashField, CommandFlags flags = CommandFlags.None)
        {
            return database.HashGetAsync(key, hashField, flags).ContinueWith(task =>
            {
                var value = task.Result;
                if (value.HasValue)
                {
                    var item = JsonSerializer.DeserializeFromString<TItem>(value);
                    return item;
                }
                else
                {
                    return default(TItem);
                }
            });
        }

        public static Dictionary<string, TItem> HashGetAll<TItem>(this IDatabase database, RedisKey key, CommandFlags flags = CommandFlags.None)
        {
            var values = database.HashGetAll(key, flags);
            if (values == null) return null;
            if (values.Length == 0) return new Dictionary<string, TItem>();
            var dict = new Dictionary<string, TItem>(values.Length);
            for (int i = 0; i < values.Length; i++)
            {
                var entity = values[i];
                var item = JsonSerializer.DeserializeFromString<TItem>(entity.Value);
                dict.Add(entity.Name, item);
            }
            return dict;
        }

        public static Task<Dictionary<string, TItem>> HashGetAllAsync<TItem>(this IDatabase database, RedisKey key, CommandFlags flags = CommandFlags.None)
        {
            return database.HashGetAllAsync(key, flags).ContinueWith(task =>
            {
                var values = task.Result;
                if (values == null) return null;
                if (values.Length == 0) return new Dictionary<string, TItem>();
                var dict = new Dictionary<string, TItem>(values.Length);
                for (int i = 0; i < values.Length; i++)
                {
                    var entity = values[i];
                    var item = JsonSerializer.DeserializeFromString<TItem>(entity.Value);
                    dict.Add(entity.Name, item);
                }
                return dict;
            });
        }

        public static void HashSet<TItem>(this IDatabase database, RedisKey key, Dictionary<string, TItem> keyValues, CommandFlags flags = CommandFlags.None)
        {
            if (keyValues == null || keyValues.Count == 0) return;
            HashEntry[] hashFields = new HashEntry[keyValues.Count];
            var index = 0;
            foreach (var kv in keyValues)
            {
                var value = JsonSerializer.SerializeToString(kv.Value);
                hashFields[index++] = new HashEntry(kv.Key, value);
            }
            database.HashSet(key, hashFields, flags);
        }

        public static Task HashSetAsync<TItem>(this IDatabase database, RedisKey key, Dictionary<string, TItem> keyValues, CommandFlags flags = CommandFlags.None)
        {
            if (keyValues == null || keyValues.Count == 0) return new Task(() => { });
            HashEntry[] hashFields = new HashEntry[keyValues.Count];
            var index = 0;
            foreach (var kv in keyValues)
            {
                var value = JsonSerializer.SerializeToString(kv.Value);
                hashFields[index++] = new HashEntry(kv.Key, value);
            }
            return database.HashSetAsync(key, hashFields, flags);
        }

        public static bool HashSet<TItem>(this IDatabase database, RedisKey key, RedisValue hashField, TItem item, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            RedisValue value = JsonSerializer.SerializeToString(item);
            return database.HashSet(key, hashField, value, when, flags);
        }

        public static Task<bool> HashSetAsync<TItem>(this IDatabase database, RedisKey key, RedisValue hashField, TItem item, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            var value = JsonSerializer.SerializeToString(item);
            return database.HashSetAsync(key, hashField, value, when, flags);
        }

        public static TItem[] HashValues<TItem>(this IDatabase database, RedisKey key, CommandFlags flags = CommandFlags.None)
        {
            var values = database.HashValues(key, flags);
            if (values == null) return null;
            if (values.Length == 0) return new TItem[0];
            TItem[] items = new TItem[values.Length];
            for (int i = 0; i < values.Length; i++)
            {
                items[i] = JsonSerializer.DeserializeFromString<TItem>(values[i]);
            }
            return items;
        }

        public static Task<TItem[]> HashValuesAsync<TItem>(this IDatabase database, RedisKey key, CommandFlags flags = CommandFlags.None)
        {
            return database.HashValuesAsync(key, flags).ContinueWith(task =>
           {
               var values = task.Result;
               if (values == null) return null;
               if (values.Length == 0) return new TItem[0];
               TItem[] items = new TItem[values.Length];
               for (int i = 0; i < values.Length; i++)
               {
                   items[i] = JsonSerializer.DeserializeFromString<TItem>(values[i]);
               }
               return items;
           });

        }

    }
}
